#include"interrupt.h"
#include"os_type.h"
#include"os_constant.h"
#include"os_modules.h"
#include"asm_utils.h"
#include"stdio.h"
#include"program.h"

int times=0;

InterruptManager::InterruptManager()
{
	initialize();
}

void InterruptManager::initialize()
{
	times=0;//初始化中断计数变量

	//初始化IDT
	IDT = (uint32*)IDT_START_ADDRESS;
	asm_lidt(IDT_START_ADDRESS,256*8-1);//表的界限
	for(uint i=0; i<256; i++)
	{
		setInterruptDescriptor(i,(uint32)asm_unhandled_interrupt,0);
	}
	initialize8259A();//初始化8259A芯片
}
void InterruptManager::setInterruptDescriptor(uint32 index,uint32 address,byte DPL)
{
	//中断描述符的低32位
	IDT[index*2] = (CODE_SELECTOR << 16) | (address & 0xffff);
	//中断描述符的高32位
	IDT[index*2+1] = (address & 0xffff0000) | (0x1 << 15) | (DPL << 13) | (0xe << 8);
}
void InterruptManager::initialize8259A()
{
	//ICW1
	asm_out_port(0x20,0x11);
	asm_out_port(0xa0,0x11);
	//ICW2
	IRQ0_8259A_MASTER=0x20;
	IRQ0_8259A_SLAVE=0x28;
	asm_out_port(0x21,IRQ0_8259A_MASTER);
	asm_out_port(0xa1,IRQ0_8259A_SLAVE);
	//ICW3
	asm_out_port(0x21,4);
	asm_out_port(0xa1,2);
	//ICW4
	asm_out_port(0x21,1);
	asm_out_port(0xa1,1);

	//OCW1 屏蔽主片所有中断，但主片的IRQ2需要开启
	asm_out_port(0x21,0xfb);
	//OCW1 屏蔽从片所有中断
	asm_out_port(0xa1,0xff);
}
void InterruptManager::enableTimeInterrupt()
{
	uint8 value;
	//读入主片OCW
	asm_in_port(0x21,&value);
	//开启主片时钟中断，置0开启
	value=value&0xfe;
	asm_out_port(0x21,value);
}
void InterruptManager::disableTimeInterrupt()
{
	uint8 value;
	asm_in_port(0x21,&value);
	//关闭时钟中断，置1关闭
	value=value | 0x01;
	asm_out_port(0x21,value);
}
void InterruptManager::setTimeInterrupt(void* handler)
{
	setInterruptDescriptor(IRQ0_8259A_MASTER,(uint32)handler,0);
}
//中断处理函数
extern "C" void c_time_interrupt_handler()
{
	programManager.age();
	PCB* cur=programManager.running;
	if(cur->ticks)
	{
		cur->ticks--;
		cur->ticksPassedBy++;
	}else{
		programManager.schedule_multilevel_feedback_queue();
		// programManager.schedule_round_robin();
	}

	/*//清空屏幕
	for(int i=0; i<80; i++)
	{
		stdio.print(0,i,' ',0x04);
	}

	//输出中断发生的次数
	++times;

    //输出跑马灯学号
	char message[]="22336271ysj";
	int index=(times/7)%11;
	stdio.moveCursor(0,index);
	stdio.print(message[index],0x05); 
	
	 //输出中断次数
	char str[]="interrupt happened: ";
	char number[12];
	int temp=times;
	
	//将数字转换为字符串表示
	for(int i=0; i<10; ++i)
	{
		if(temp){
			number[i]=temp%10+'0';
		}else{
			number[i]='0';
		}
		temp /= 10;
	}

	//移动光标到(0,0)输出字符
	stdio.moveCursor(0);
	for(int i=0; str[i]; ++i)
	{
		stdio.print(str[i]);
	}

	//输出中断发生的次数
	for(int i=9; i>=0; --i)
	{
		stdio.print(number[i]);
	}*/ 
}
void InterruptManager::enableKeyboardInterrupt()
{
	uint8 value;
	asm_in_port(0x21,&value);
	//主片第二个中断向量号
	value=value&0xfd;
	asm_out_port(0x21,value);
}
void InterruptManager::disableKeyboardInterrupt()
{
	uint8 value;
	asm_in_port(0x21,&value);
	value=value|0x02;
	asm_out_port(0x21,value);
}
void InterruptManager::setKeyboardInterrupt(void* handler)
{
	setInterruptDescriptor(IRQ0_8259A_MASTER+1,(uint32)handler,0);
}
extern "C" void c_keyboard_interrupt_handler(uint32 scan_code)
{
	stdio.handleKeyboard(scan_code);
}
void InterruptManager::enableInterrupt()
{
	asm_enable_interrupt();
}
void InterruptManager::disableInterrupt()
{
	asm_disable_interrupt();
}
bool InterruptManager::getInterruptStatus()
{
	return asm_interrupt_status()?true:false;
}
void InterruptManager::setInterruptStatus(bool status)
{
	if(status) enableInterrupt();
	else disableInterrupt();
}	